<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <!-- hexo-inject:begin --><!-- hexo-inject:end --><meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 3.9.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"mjava.top","root":"/","scheme":"Muse","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":true},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="浅水是喧哗的，深水是沉默的">
<meta name="keywords" content="Java,Linux,Spring,Jenkins,Docker,RocketMQ,Vue">
<meta property="og:type" content="website">
<meta property="og:title" content="灰色World">
<meta property="og:url" content="http://mjava.top/page/3/index.html">
<meta property="og:site_name" content="灰色World">
<meta property="og:description" content="浅水是喧哗的，深水是沉默的">
<meta property="og:locale" content="zh-CN">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="灰色World">
<meta name="twitter:description" content="浅水是喧哗的，深水是沉默的">

<link rel="canonical" href="http://mjava.top/page/3/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : true,
    isPost : false,
    lang   : 'zh-CN'
  };
</script>

  <title>灰色World</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="灰色World" type="application/atom+xml"><!-- hexo-inject:begin --><!-- hexo-inject:end -->
<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head>

<body itemscope itemtype="http://schema.org/WebPage">
  <!-- hexo-inject:begin --><!-- hexo-inject:end --><div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">灰色World</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/greycode9" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener external nofollow noreferrer" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content index posts-expand">
            
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/archive/web-security/sso-and-cas/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/archive/web-security/sso-and-cas/" class="post-title-link" itemprop="url">SSO单点登录和CAS框架</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-05-14 19:27:14" itemprop="dateCreated datePublished" datetime="2020-05-14T19:27:14+00:00">2020-05-14</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/WebSecurity/" itemprop="url" rel="index"><span itemprop="name">WebSecurity</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="SSO单点登录"><a href="#SSO单点登录" class="headerlink" title="SSO单点登录"></a>SSO单点登录</h2><p><strong>单点登录</strong>（英语：Single sign-on，缩写为 SSO），又译为<strong>单一签入</strong>，一种对于许多相互关连，但是又是各自独立的软件系统，提供<a href="https://zh.wikipedia.org/wiki/存取控制" rel="noopener external nofollow noreferrer" target="_blank">访问控制</a>的属性。当拥有这项属性时，当用户<a href="https://zh.wikipedia.org/wiki/登入" rel="noopener external nofollow noreferrer" target="_blank">登录</a>时，就可以获取所有系统的访问权限，不用对每个单一系统都逐一登录。这项功能通常是以<a href="https://zh.wikipedia.org/wiki/轻型目录访问协议" rel="noopener external nofollow noreferrer" target="_blank">轻型目录访问协议</a>（LDAP）来实现，在服务器上会将用户信息存储到LDAP数据库中。相同的，<strong>单一退出</strong>（single sign-off）就是指，只需要单一的退出动作，就可以结束对于多个系统的访问权限。</p>
<h3 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h3><p>使用单点登录的好处包括：</p>
<ul>
<li>降低访问第三方网站的风险（不存储用户密码，或在外部管理）。</li>
<li>减少因不同的用户名和密码组合而带来的<a href="https://zh.wikipedia.org/w/index.php?title=密碼疲勞&action=edit&redlink=1" rel="noopener external nofollow noreferrer" target="_blank">密码疲劳</a>。</li>
<li>减少为相同的身份重新输入密码所花费的时间。</li>
<li>因减少与密码相关的调用IT<a href="https://zh.wikipedia.org/wiki/服务台" rel="noopener external nofollow noreferrer" target="_blank">服务台</a>的次数而降低IT成本。<a href="https://zh.wikipedia.org/wiki/單一登入#cite_note-1" rel="noopener external nofollow noreferrer" target="_blank">[1]</a></li>
</ul>
<p>SSO为所有其它应用程序和系统，以集中的<a href="https://zh.wikipedia.org/w/index.php?title=验证服务器&action=edit&redlink=1" rel="noopener external nofollow noreferrer" target="_blank">验证服务器</a>提供身份验证，并结合技术以确保用户不必频繁输入密码。</p>
<h2 id="CAS框架"><a href="#CAS框架" class="headerlink" title="CAS框架"></a>CAS框架</h2><p>CAS 协议基于在<strong>客户端</strong>Web浏览器、Web<strong>应用</strong>和<strong>CAS服务器</strong>之间的票据验证。当客户端访问访问应用程序，请求身份验证时，应用程序重定向到CAS。CAS验证客户端是否被授权，通常通过在数据库对用户名和密码进行检查。如果身份验证成功，CAS一次性在客户端以Cookie形式发放TGT票据，在其有效期CAS将一直信任用户，同时将客户端自动返回到应用程序，并向应用传递身份验证票（Service ticket）。然后，应用程序通过安全连接连接CAS，并提供自己的服务标识和验证票。之后CAS给出了关于特定用户是否已成功通过身份验证的应用程序授信信息。</p>
<h3 id="历史"><a href="#历史" class="headerlink" title="历史"></a>历史</h3><ul>
<li><p>CAS是由<a href="https://zh.wikipedia.org/wiki/耶鲁大学" rel="noopener external nofollow noreferrer" target="_blank">耶鲁大学</a><a href="https://zh.wikipedia.org/wiki/集中式认证服务#cite_note-1" rel="noopener external nofollow noreferrer" target="_blank">[1]</a>的Shawn Bayern创始的，后来由耶鲁大学的Drew Mazurek维护。CAS1.0实现了单点登录。 CAS2.0引入了多级代理认证（Multi-tier proxy authentication）。CAS其他几个版本已经有了新的功能。</p>
</li>
<li><p>2004年12月，CAS成为<a href="https://zh.wikipedia.org/w/index.php?title=Jasig&action=edit&redlink=1" rel="noopener external nofollow noreferrer" target="_blank">Jasig</a><a href="https://zh.wikipedia.org/wiki/集中式认证服务#cite_note-2" rel="noopener external nofollow noreferrer" target="_blank">[2]</a>的一个项目，2008年该组织负责CAS的维护和发展。CAS原名“耶鲁大学CAS”，此后被称为“Jasig CAS”。</p>
</li>
<li><p>2005年5月，CAS协议版本2发布，引入代理和服务验证。</p>
</li>
<li><p>2006年12月，<a href="https://zh.wikipedia.org/w/index.php?title=安德鲁·W·梅隆基金会&action=edit&redlink=1" rel="noopener external nofollow noreferrer" target="_blank">安德鲁·W·梅隆基金会</a>授予耶鲁大学第一届梅隆技术协作奖，颁发50000美元的奖金对耶鲁大学开发CAS进行奖励。<a href="https://zh.wikipedia.org/wiki/集中式认证服务#cite_note-3" rel="noopener external nofollow noreferrer" target="_blank">[3]</a>颁奖之时，CAS在“数以百计的大学校园”中使用。</p>
</li>
<li><p>2012年12月，JASIG与Sakai基金合并，CAS改名为Apereo CAS。</p>
</li>
<li><p>2016年11月，基于Spring Boot的CAS软件版本5发布。</p>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/archive/web-security/oauth-and-jwt/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/archive/web-security/oauth-and-jwt/" class="post-title-link" itemprop="url">OAuth2.0与JWT</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-05-12 14:59:43" itemprop="dateCreated datePublished" datetime="2020-05-12T14:59:43+00:00">2020-05-12</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/WebSecurity/" itemprop="url" rel="index"><span itemprop="name">WebSecurity</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="OAuth2-0"><a href="#OAuth2-0" class="headerlink" title="OAuth2.0"></a>OAuth2.0</h2><p>OAuth2.0是一个授权协议，它允许软件应用代表资源拥有者去访问资源拥有者的资源。应用向资源拥有者请求<code>令牌</code>，并用这个令牌来访问资源拥有者的资源。</p>
<h3 id="角色"><a href="#角色" class="headerlink" title="角色"></a>角色</h3><ul>
<li>客户端：相当于访问受保护资源的软件</li>
<li>授权服务器：授予客户端令牌的服务</li>
<li>资源拥有者：受保护的资源拥有者，有权决定将不将令牌授权给客户端</li>
<li>受保护的资源：除资源拥有者外，要访问此资源必须要有授权服务器颁发的有效的令牌</li>
</ul>
<h3 id="授权类型"><a href="#授权类型" class="headerlink" title="授权类型"></a>授权类型</h3><h4 id="授权码许可类型"><a href="#授权码许可类型" class="headerlink" title="授权码许可类型"></a>授权码许可类型<img src="http://cdn.mjava.top/blog/20200512090246.jpg" alt="授权码许可类型"></h4><hr>
<h4 id="隐式许可类型"><a href="#隐式许可类型" class="headerlink" title="隐式许可类型"></a>隐式许可类型<img src="http://cdn.mjava.top/blog/20200512135621.jpg" alt="隐式许可类型"></h4><hr>
<h4 id="客户端凭证许可类型"><a href="#客户端凭证许可类型" class="headerlink" title="客户端凭证许可类型"></a>客户端凭证许可类型<img src="http://cdn.mjava.top/blog/20200512135605.jpg" alt="客户端凭证许可类型"></h4><hr>
<h4 id="资源拥有者凭证许可类型-账号密码模式"><a href="#资源拥有者凭证许可类型-账号密码模式" class="headerlink" title="资源拥有者凭证许可类型(账号密码模式)"></a>资源拥有者凭证许可类型(账号密码模式)<img src="http://cdn.mjava.top/blog/20200512135635.jpg" alt="资源拥有者凭证许可类型(账号密码模式)"></h4><hr>
<h4 id="断言许可类型"><a href="#断言许可类型" class="headerlink" title="断言许可类型"></a>断言许可类型<img src="http://cdn.mjava.top/blog/20200512135531.jpg" alt="断言许可类型"></h4><h2 id="JWT"><a href="#JWT" class="headerlink" title="JWT"></a>JWT</h2><p>JWT全称：JSON Web Token，是一种令牌格式。其格式类似为<code>xxxxx.yyyyy.zzzzz</code>,分为三部分，每个部分都用<code>Base64</code>进行编码，之间用<code>.</code>分隔。</p>
<p>第一部分：为Header部分，标头通常由两部分组成：令牌的类型（即JWT）和所使用的签名算法，例如HMAC SHA256或RSA。</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"alg"</span>: <span class="string">"HS256"</span>,</span><br><span class="line">  <span class="attr">"typ"</span>: <span class="string">"JWT"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第二部分：令牌的第二部分是有效负载，其中包含声明。 声明是有关实体（通常是用户）和其他数据的声明。 共有三种类型的声明：注册的，公共的和私有的三种声明。当然里面可以存放任何有效的字段信息（私有声明）。但是为了避免不同实现之间不兼容，可以准守JWT官方提供的声明字段。</p>
<ul>
<li>注册声明：JWT官方提供的声明，参考资料:<a href="https://tools.ietf.org/html/rfc7519#section-4.1" rel="noopener external nofollow noreferrer" target="_blank">https://tools.ietf.org/html/rfc7519#section-4.1</a></li>
<li>公共声明：用户发邮件给JWT官方进行注册的声明字段，参考资料：<a href="https://tools.ietf.org/html/rfc7519#section-4.2" rel="noopener external nofollow noreferrer" target="_blank">https://tools.ietf.org/html/rfc7519#section-4.2</a></li>
<li>私有声明：完全用户自定义，参考资料<a href="https://tools.ietf.org/html/rfc7519#section-4.3" rel="noopener external nofollow noreferrer" target="_blank">https://tools.ietf.org/html/rfc7519#section-4.3</a></li>
</ul>
<p>第三部分：为令牌签名部分，使用这个字段后，资源服务器只会接受签名正确的令牌。</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/linux/linux-fastdfs-install/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/linux/linux-fastdfs-install/" class="post-title-link" itemprop="url">fastDFS安装使用教程</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-05-07 13:34:10" itemprop="dateCreated datePublished" datetime="2020-05-07T13:34:10+00:00">2020-05-07</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index"><span itemprop="name">Linux</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="FastDFS简介"><a href="#FastDFS简介" class="headerlink" title="FastDFS简介"></a>FastDFS简介</h2><p>FastDFS 是一个开源的高性能分布式文件系统（DFS）。 它的主要功能包括：文件存储，文件同步和文件访问，以及高容量和负载平衡。主要解决了海量数据存储问题，特别适合以中小文件（建议范围：4KB &lt; file_size &lt;500MB）为载体的在线服务。</p>
<p>FastDFS 系统有三个角色：跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client)。</p>
<ul>
<li><p><strong>Tracker Server</strong>：跟踪服务器，主要做调度工作，起到均衡的作用；负责管理所有的 storage server和 group，每个 storage 在启动后会连接 Tracker，告知自己所属 group 等信息，并保持周期性心跳。</p>
</li>
<li><p><strong>Storage Server</strong>：存储服务器，主要提供容量和备份服务；以 group 为单位，每个 group 内可以有多台 storage server，数据互为备份。</p>
</li>
<li><p><strong>Client</strong>：客户端，上传下载数据的服务器，也就是我们自己的项目所部署在的服务器。</p>
</li>
<li><p>结构图<img src="http://cdn.mjava.top/blog/20200507152801.webp" alt></p>
</li>
</ul>
<ul>
<li>上传文件流程<img src="http://cdn.mjava.top/blog/20200507152857.webp" alt></li>
</ul>
<h2 id="安装环境"><a href="#安装环境" class="headerlink" title="安装环境"></a>安装环境</h2><table>
<thead>
<tr>
<th>系统及软件版本</th>
<th>Git开源地址</th>
</tr>
</thead>
<tbody><tr>
<td>Centos 7</td>
<td>#</td>
</tr>
<tr>
<td>libfastcommon V1.0.43</td>
<td><a href="https://github.com/happyfish100/fastdfs" rel="noopener external nofollow noreferrer" target="_blank">https://github.com/happyfish100/fastdfs</a></td>
</tr>
<tr>
<td>fastdfs V6.06</td>
<td><a href="https://github.com/happyfish100/libfastcommon" rel="noopener external nofollow noreferrer" target="_blank">https://github.com/happyfish100/libfastcommon</a></td>
</tr>
</tbody></table>
<blockquote>
<p>我虚拟机装的Centos7的ip地址是172.16.54.137</p>
</blockquote>
<h2 id="安装前工作"><a href="#安装前工作" class="headerlink" title="安装前工作"></a>安装前工作</h2><h3 id="关闭防火墙"><a href="#关闭防火墙" class="headerlink" title="关闭防火墙"></a>关闭防火墙</h3><blockquote>
<p>为了方便，先关闭防火墙。线上环境安装可安装后开放对应端口。</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">service firewalld stop</span><br></pre></td></tr></table></figure>

<h3 id="下载所需安装包"><a href="#下载所需安装包" class="headerlink" title="下载所需安装包"></a>下载所需安装包</h3><ul>
<li>libfastcommon</li>
</ul>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">wget https://github.com/happyfish100/libfastcommon/archive/V1.0.43.tar.gz -O libfastcommon.tar.gz</span><br></pre></td></tr></table></figure>

<ul>
<li>fastDFS</li>
</ul>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">wget https://github.com/happyfish100/fastdfs/archive/V6.06.tar.gz -O fastdfs.tar.gz</span><br></pre></td></tr></table></figure>

<h3 id="安装fastDFS环境"><a href="#安装fastDFS环境" class="headerlink" title="安装fastDFS环境"></a>安装fastDFS环境</h3><ul>
<li>解压安装<code>libfastcommon</code></li>
</ul>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">tar -zxvf libfastcommon.tar.gz &amp;&amp; cd libfastcommon-1.0.43/ &amp;&amp; ./make.sh &amp;&amp; ./make.sh install</span><br></pre></td></tr></table></figure>

<h2 id="安装fastDFS"><a href="#安装fastDFS" class="headerlink" title="安装fastDFS"></a>安装fastDFS</h2><h3 id="解压安装"><a href="#解压安装" class="headerlink" title="解压安装"></a>解压安装</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">tar -zxvf fastdfs.tar.gz &amp;&amp; cd fastdfs-6.06/ &amp;&amp; ./make.sh &amp;&amp; ./make.sh install</span><br></pre></td></tr></table></figure>

<blockquote>
<p>安装好fastDFS后，在<code>/etc/fdfs/</code>目录下会生成4个示例的配置文件</p>
<ul>
<li>client.conf.sample    fastDFS客户端配置文件</li>
<li>storage.conf.sample</li>
<li>storage_ids.conf.sample    当storage超过1个时，可以用这个配置文件来配置管理</li>
<li>tracker.conf.sample</li>
</ul>
</blockquote>
<h3 id="配置并启动Tracker"><a href="#配置并启动Tracker" class="headerlink" title="配置并启动Tracker"></a>配置并启动Tracker</h3><p>进入<code>/etc/fdfs/</code>复制一份<code>Tracker</code>配置文件，</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd /etc/fdfs/ &amp;&amp; cp tracker.conf.sample tracker.conf</span><br></pre></td></tr></table></figure>

<p>修改<code>tracker.conf</code>配置文件里的<code>base_path</code>目录</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">base_path=/data/fastdfs/tracker</span><br></pre></td></tr></table></figure>

<p>创建对应的文件夹</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mkdir -p /data/fastdfs/tracker</span><br></pre></td></tr></table></figure>

<p>服务命令</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">启动Tracker</span></span><br><span class="line">service fdfs_trackerd start</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">关闭Tracker</span></span><br><span class="line">service fdfs_trackerd stop</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">开机自启</span></span><br><span class="line">systemctl enable fdfs_trackerd</span><br></pre></td></tr></table></figure>

<h3 id="配置并启动Storage"><a href="#配置并启动Storage" class="headerlink" title="配置并启动Storage"></a>配置并启动Storage</h3><p>进入<code>/etc/fdfs/</code>复制一份<code>Storage</code>配置文件，</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd /etc/fdfs &amp;&amp; cp storage.conf.sample storage.conf</span><br></pre></td></tr></table></figure>

<p>修改<code>storage.conf</code>配置文件</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">base_path=/data/fastdfs/storage</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">存放文件地址</span></span><br><span class="line">store_path0=/data/fastdfs/file</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">更改为你的tracker地址</span></span><br><span class="line">tracker_server=172.16.54.137:22122</span><br></pre></td></tr></table></figure>

<p>创建对应的文件夹</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mkdir -p /data/fastdfs/storage &amp;&amp; mkdir -p /data/fastdfs/file</span><br></pre></td></tr></table></figure>

<p>服务命令</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">启动Storage</span></span><br><span class="line">service fdfs_storaged start</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">关闭Storage</span></span><br><span class="line">service fdfs_storaged stop</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">开机自启</span></span><br><span class="line">systemctl enable fdfs_storaged</span><br></pre></td></tr></table></figure>

<h3 id="上传文件测试"><a href="#上传文件测试" class="headerlink" title="上传文件测试"></a>上传文件测试</h3><blockquote>
<p>上传文件可以用他自带的客户端进行测试，使用客户端前，要复制一份<code>client.conf</code>并修改一下里面的内容</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">复制一份客户端配置文件</span></span><br><span class="line">cd /etc/fdfs &amp;&amp; cp client.conf.sample client.conf</span><br></pre></td></tr></table></figure>

<p>修改<code>client.config</code>配置文件</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">base_path=/data/fastdfs/client</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">更改为你的tracker地址</span></span><br><span class="line">tracker_server=172.16.54.137:22122</span><br></pre></td></tr></table></figure>

<p>创建对应文件夹</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">mkdir -p /data/fastdfs/client</span><br></pre></td></tr></table></figure>

<p>使用方法</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">/usr/bin/fdfs_upload_file /etc/fdfs/client.conf [filename]</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">上传成功后返回</span></span><br><span class="line">group1/M00/00/00/rBA2iV6yvU2AEXUfAAACGTXt3Kw94.yaml</span><br></pre></td></tr></table></figure>

<p><img src="http://cdn.mjava.top/blog/20200506215501.png" alt></p>
<h2 id="安装Nginx"><a href="#安装Nginx" class="headerlink" title="安装Nginx"></a>安装Nginx</h2><blockquote>
<p>为了方便，这里直接使用nginx的docker镜像来进行安装。docker安装请自行查找资料</p>
</blockquote>
<p>首先创建一个文件夹，存放nginx的配置文件</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">创建文件夹</span></span><br><span class="line">mkdir -p /data/nginx</span><br><span class="line"><span class="meta">#</span><span class="bash">进入文件夹并下载nginx配置文件</span></span><br><span class="line">cd /data/nginx &amp;&amp; wget http://cdn.mjava.top/file/nginx.conf</span><br></pre></td></tr></table></figure>

<blockquote>
<p>配置文件已经修改过了，直接下载即可使用</p>
</blockquote>
<p>然后运行docker命令（第一次运行会自动下载nginx镜像）</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker run -d -p 81:80 -v /data/nginx/nginx.conf:/etc/nginx/nginx.conf -v /data/:/data/ --name fastDFS-nginx nginx</span><br></pre></td></tr></table></figure>

<p>然后就可以通过<code>http://ip:port/[filePth]</code>访问上传到fastDFS的文件了</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">例如刚才上传的文件 可以通过如下地址访问</span></span><br><span class="line">http://172.16.54.137:81/group1/M00/00/00/rBA2iV6yvU2AEXUfAAACGTXt3Kw94.yaml</span><br></pre></td></tr></table></figure>

<h2 id="拓展"><a href="#拓展" class="headerlink" title="拓展"></a>拓展</h2><p>这里只是示例了单机的fastDFS安装，一般fastDFS都是分布式安装的。具体可以通过下载这个结构图去进行安装。此时如果配置了多个group，则需要安装<code>fastdfs-nginx-module</code>这个nginx的模块。</p>
<p><img src="http://cdn.mjava.top/blog/20200507132841.png" alt></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/mysql/mysql-utf8mb4-error/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/mysql/mysql-utf8mb4-error/" class="post-title-link" itemprop="url">插入emoji到mysql时提示了一个表里不存在的字段的错误</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-04-29 17:16:27" itemprop="dateCreated datePublished" datetime="2020-04-29T17:16:27+00:00">2020-04-29</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/MySQL/" itemprop="url" rel="index"><span itemprop="name">MySQL</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="1-问题描述"><a href="#1-问题描述" class="headerlink" title="1.问题描述"></a>1.问题描述</h2><p>由于公司前端有需求，需要在<code>tiny_user_info</code>表的<code>nickname</code>这个字段里存入emoji表情，于是我熟练地将这个字段修改为<code>utf8mb4</code>，改好后测试插入一条带emoji数据。于是报了这个错误：</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[2020-04-29 15:57:25] [HY000][1366] Incorrect string value: '\xF0\x9F\x98\x98' for column 'user_name' at row 14</span><br></pre></td></tr></table></figure>

<p>当时我就傻了，我这个表里也没有<code>user_name</code>这个字段啊，怎么会报这个字段错误,我明明修改的是<code>nickname</code>这个字段啊。于是google和百度搜了一圈，无解。</p>
<h2 id="２-解决方案"><a href="#２-解决方案" class="headerlink" title="２.解决方案"></a>２.解决方案</h2><p>试了好几种方法，删字段，重新建。删表，重新建。都不行。。。。。静下心来，于是打算从mysql服务器入手。进入到mysql对应库的文件夹，发现<code>tiny_user_info</code>这个表有三个文件</p>
<p><img src="http://cdn.mjava.top/blog/20200429171012.png" alt></p>
<p>和常见的多了一个<code>TRG</code>文件。这是一个触发器文件，打开一看，发现了<code>user_name</code>字段。。。。。。</p>
<p>原来是同事在这个表里加了个触发器，当<code>tiny_user_info</code>里新增数据时，会触发新增到另一张表里，<code>nickname</code>的值同时会插入到另一张表的<code>user_name</code>字段，而他那张表的字段没有设置<code>utf8mb4编码</code>,所以导致插入失败。于是叫同事把他那张表设置一下<code>utf8mb4</code>编码后，就可以正常插入了。</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/algorithm/algorithm-avltree-01/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/algorithm/algorithm-avltree-01/" class="post-title-link" itemprop="url">【数据结构】手写平衡二叉树（AVL）</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-02-01 15:56:00" itemprop="dateCreated datePublished" datetime="2020-02-01T15:56:00+00:00">2020-02-01</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Algorithm/" itemprop="url" rel="index"><span itemprop="name">Algorithm</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="【数据结构】手写平衡二叉树（AVL）"><a href="#【数据结构】手写平衡二叉树（AVL）" class="headerlink" title="【数据结构】手写平衡二叉树（AVL）"></a>【数据结构】手写平衡二叉树（AVL）</h1><p><img src="http://cdn.mjava.top/blog/20200201165139.jpg" alt></p>
<blockquote>
<p>积千里跬步，汇万里江河。每天进步一点点，终有一天将成大佬</p>
<p>本文源代码：<a href="https://github.com/z573419235/studyDemo/blob/master/BaseJava/src/dataStructure/AVLTree.java" rel="noopener external nofollow noreferrer" target="_blank">手写AVL树</a></p>
</blockquote>
<h2 id="什么是平衡二叉树？"><a href="#什么是平衡二叉树？" class="headerlink" title="什么是平衡二叉树？"></a>什么是平衡二叉树？</h2><p>平衡二叉树，又称为AVL树，当树不是空树时，它的左右两个子树的高度差的绝对值不超过1，并且左右两个子树都是一棵<a href="https://baike.baidu.com/item/平衡二叉树/10421057" rel="noopener external nofollow noreferrer" target="_blank">平衡二叉树</a>。AVL树查找的时间复杂度为O(logN)。</p>
<h3 id="平衡二叉树基本特点"><a href="#平衡二叉树基本特点" class="headerlink" title="平衡二叉树基本特点"></a>平衡二叉树基本特点</h3><ul>
<li>左右子树深度差不能大于1</li>
<li>左边子树永远比根节点小</li>
<li>右边子树永远比根节点大</li>
</ul>
<h3 id="平衡二叉树基本结构及操作"><a href="#平衡二叉树基本结构及操作" class="headerlink" title="平衡二叉树基本结构及操作"></a>平衡二叉树基本结构及操作</h3><ul>
<li>左左结构——右旋</li>
</ul>
<p><img src="http://cdn.mjava.top/blog/20200201153234.jpg" alt="左左结构"></p>
<ul>
<li>右右结构——左旋</li>
</ul>
<p><img src="http://cdn.mjava.top/blog/20200201153301.jpg" alt="右右结构"></p>
<ul>
<li>左右结构——左子先左旋，然后整体右旋</li>
</ul>
<p><img src="http://cdn.mjava.top/blog/20200201153329.jpg" alt="左右结构"></p>
<ul>
<li>右左结构——右子先右旋，然后整体左旋</li>
</ul>
<p><img src="http://cdn.mjava.top/blog/20200201153403.jpg" alt="右左结构"></p>
<h2 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h2><p>先创建一个内部类Node，来表示树的每个节点</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AVLTree</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Node rootNode;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//二叉树节点</span></span><br><span class="line">    <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span></span>&#123;</span><br><span class="line">        <span class="keyword">public</span> Node parent; <span class="comment">//父</span></span><br><span class="line">        <span class="keyword">public</span> Node left;	<span class="comment">//左子树</span></span><br><span class="line">        <span class="keyword">public</span> Node right;	<span class="comment">//右子树</span></span><br><span class="line">        <span class="meta">@NotNull</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">int</span> data;	<span class="comment">//存放的数据</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> depth;	<span class="comment">//深度</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> balance;	<span class="comment">//平衡因子</span></span><br><span class="line">		<span class="comment">//有参构造方法</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(<span class="keyword">int</span> data)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.data=data;</span><br><span class="line">            <span class="keyword">this</span>.depth=<span class="number">1</span>;</span><br><span class="line">            <span class="keyword">this</span>.balance=<span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="插入数据"><a href="#插入数据" class="headerlink" title="插入数据"></a>插入数据</h3><p>暴露一个方法给外部调用</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**添加数据方法*/</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> data)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.rootNode==<span class="keyword">null</span>)&#123;</span><br><span class="line">        <span class="keyword">this</span>.rootNode=<span class="keyword">new</span> Node(data);</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">this</span>.insert(rootNode,data);</span><br><span class="line">        <span class="comment">//判断根节点是否有父  有的话说明有旋转操作，更新根节点</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">this</span>.rootNode.parent!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">this</span>.rootNode=<span class="keyword">this</span>.rootNode.parent;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>实际内部是调用另一个<code>insert</code>方法：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(Node root,<span class="keyword">int</span> data)</span></span>&#123;</span><br><span class="line">    <span class="comment">//插入的数据比根小</span></span><br><span class="line">    <span class="keyword">if</span> (data&lt;root.data)&#123;</span><br><span class="line">        <span class="keyword">if</span> (root.left==<span class="keyword">null</span>)&#123;</span><br><span class="line">            root.left=<span class="keyword">new</span> Node(data);</span><br><span class="line">            root.left.parent=root;</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">this</span>.insert(root.left,data);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//插入的数据比根大</span></span><br><span class="line">    <span class="keyword">if</span> (data&gt;root.data)&#123;</span><br><span class="line">        <span class="keyword">if</span> (root.right==<span class="keyword">null</span>) &#123;</span><br><span class="line">            root.right=<span class="keyword">new</span> Node(data);</span><br><span class="line">            root.right.parent=root;</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.insert(root.right,data);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    root.balance=<span class="keyword">this</span>.getBalance(root);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (root.balance&gt;<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">//判断左子的平衡因子</span></span><br><span class="line">        <span class="keyword">if</span> (root.left.balance&lt;<span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">this</span>.leftTurn(root.left);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.rightTurn(root);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (root.balance&lt;-<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">//判断右子的平衡因子</span></span><br><span class="line">        <span class="keyword">if</span> (root.right.balance&gt;<span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">this</span>.rightTurn(root.right);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">this</span>.leftTurn(root);</span><br><span class="line">    &#125;</span><br><span class="line">    root.depth=<span class="keyword">this</span>.getDepth(root);</span><br><span class="line">    root.balance=<span class="keyword">this</span>.getBalance(root);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="右旋"><a href="#右旋" class="headerlink" title="右旋"></a>右旋</h3><blockquote>
<p>右旋的操作如下</p>
<ul>
<li>我父变成左子的父</li>
<li>左子变成我的父</li>
<li>我变成左子的右子</li>
<li>左子的右子变成我的左子</li>
<li>(当左子的右子存在时)我变成左子的右子的父</li>
<li>计算左右节点的深度</li>
<li>计算深度差</li>
</ul>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">rightTurn</span><span class="params">(@NotNull Node node)</span></span>&#123;</span><br><span class="line">    Node parent=node.parent;</span><br><span class="line">    Node leftSon=node.left;</span><br><span class="line">    Node leftSon_rightSon=leftSon.right;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//如果父不为空，判断我是在父的左节点还是右节点</span></span><br><span class="line">    <span class="keyword">if</span> (parent!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span> (node==parent.left)&#123;</span><br><span class="line">            <span class="comment">//我在父的左节点上，把我的左子变成父的左子</span></span><br><span class="line">            parent.left=leftSon;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (node==parent.right)&#123;</span><br><span class="line">            <span class="comment">//我在父的右节点上，把我的左子变成父的右子</span></span><br><span class="line">            parent.right=leftSon;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    leftSon.parent=parent;</span><br><span class="line">    node.parent=leftSon;</span><br><span class="line">    leftSon.right=node;</span><br><span class="line">    node.left=leftSon_rightSon;</span><br><span class="line">    <span class="comment">//如果左子的右子确实存在的</span></span><br><span class="line">    <span class="keyword">if</span> (leftSon_rightSon!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        <span class="comment">//我变成左子的右子的父</span></span><br><span class="line">        leftSon_rightSon.parent=node;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//重新计算深度和平衡因子</span></span><br><span class="line">    node.depth=<span class="keyword">this</span>.getDepth(node);</span><br><span class="line">    node.balance=<span class="keyword">this</span>.getBalance(node);</span><br><span class="line">    leftSon.depth=<span class="keyword">this</span>.getDepth(leftSon);</span><br><span class="line">    leftSon.balance=<span class="keyword">this</span>.getBalance(leftSon);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="左旋"><a href="#左旋" class="headerlink" title="左旋"></a>左旋</h3><blockquote>
<p>左旋的操作如下</p>
<ul>
<li>我的父变右子的父</li>
<li>右子变成我的父</li>
<li>我变成右子的左子</li>
<li>右子的左子变成我的右子</li>
<li>(当右子的左子存在时)我变成右子的左子的父</li>
<li>计算左右节点的深度</li>
<li>计算深度差</li>
</ul>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">leftTurn</span><span class="params">(@NotNull Node node)</span></span>&#123;</span><br><span class="line">    Node parent=node.parent;</span><br><span class="line">    Node rightSon=node.right;</span><br><span class="line">    Node rightSon_leftSon=rightSon.left;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (parent!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span> (node==parent.left)&#123;</span><br><span class="line">            parent.left=rightSon;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (node==parent.right)&#123;</span><br><span class="line">            parent.right=rightSon;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    rightSon.parent=parent;</span><br><span class="line">    node.parent=rightSon;</span><br><span class="line">    rightSon.left=node;</span><br><span class="line">    node.right=rightSon_leftSon;</span><br><span class="line">    <span class="keyword">if</span> (rightSon_leftSon!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        rightSon_leftSon.parent=node;</span><br><span class="line">    &#125;</span><br><span class="line">    node.depth=<span class="keyword">this</span>.getDepth(node);</span><br><span class="line">    node.balance=<span class="keyword">this</span>.getBalance(node);</span><br><span class="line">    rightSon.depth=<span class="keyword">this</span>.getDepth(rightSon);</span><br><span class="line">    rightSon.balance=<span class="keyword">this</span>.getBalance(rightSon);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="计算深度"><a href="#计算深度" class="headerlink" title="计算深度"></a>计算深度</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**计算深度*/</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">getDepth</span><span class="params">(Node node)</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> depth = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span>(node.left==<span class="keyword">null</span> &amp;&amp; node.right!=<span class="keyword">null</span>) &#123;</span><br><span class="line">        depth=node.right.depth;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(node.right==<span class="keyword">null</span> &amp;&amp; node.left!=<span class="keyword">null</span>) &#123;</span><br><span class="line">        depth=node.left.depth;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (node.right!=<span class="keyword">null</span> &amp;&amp; node.left!=<span class="keyword">null</span>) &#123;</span><br><span class="line">        depth=Math.max(node.left.depth,node.right.depth);</span><br><span class="line">    &#125;</span><br><span class="line">    depth++;</span><br><span class="line">    <span class="keyword">return</span> depth;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="计算平衡因子"><a href="#计算平衡因子" class="headerlink" title="计算平衡因子"></a>计算平衡因子</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**计算左右深度差*/</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">getBalance</span><span class="params">(Node node)</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> leftDepth = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> rightDepth = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span>(node.left!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        leftDepth=node.left.depth;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(node.right!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        rightDepth=node.right.depth;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">         *      左减右</span></span><br><span class="line"><span class="comment">         * 为负数：右边子树高</span></span><br><span class="line"><span class="comment">         * 为正数: 左边子树高</span></span><br><span class="line"><span class="comment">         * */</span></span><br><span class="line">    <span class="keyword">return</span> leftDepth-rightDepth;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="附言"><a href="#附言" class="headerlink" title="附言"></a>附言</h2><p>如果代码和静态图看不太明白的话，这边推荐几个动画演示的网站(可能需要科学上网)：</p>
<ul>
<li><p><a href="https://visualgo.net/zh" rel="noopener external nofollow noreferrer" target="_blank">visualgo在线</a></p>
</li>
<li><p><a href="https://www.cs.usfca.edu/~galles/visualization/Algorithms.html" rel="noopener external nofollow noreferrer" target="_blank">数据结构可视化</a></p>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/recommend/recommend-tool-1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/recommend/recommend-tool-1/" class="post-title-link" itemprop="url">【转】免费可商用，最值得收藏的10个插画素材网站</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-01-16 09:24:52" itemprop="dateCreated datePublished" datetime="2020-01-16T09:24:52+00:00">2020-01-16</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Recommend/" itemprop="url" rel="index"><span itemprop="name">Recommend</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>现在插画风格的界面越来越多，网上提供的免费插图也越来越丰富。这些插图优点是表达的内容更丰富，包括：人物、商业、运动、自然、工作、幽默等等。也更适合产品类的宣传网站或者落地页。另外，矢量图的不失真在不同尺寸的显示效果上更胜一筹。花时间整理了当前全网那些优秀的10个免费插图网站，给做产品的人们节省点查找的时间，建议收藏以备后用。这些站点的素材都是免费下载可用的，而且可以免费商用。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/recommend/recommend-tool-1/">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/java/java-arraydeque-source-1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/java/java-arraydeque-source-1/" class="post-title-link" itemprop="url">【源码解析】你真的了解ArrayDeque嘛？</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-01-08 14:00:51" itemprop="dateCreated datePublished" datetime="2020-01-08T14:00:51+00:00">2020-01-08</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>LinkedList和ArrayDeque都是通过实现了Deque这个接口来获得队列和栈的功能。而Deque这个接口通过继承Queue这个接口来取得队列功能，然后在这个基础进行扩展，实现了双端队列，由此可以获得栈的功能。为了空间能得到充分利用，ArrayDeque使用了循环队列；还有LinkedList可以插入null值，而ArrayDeque是不能插入null的。</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/java/java-arraydeque-source-1/">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/java/java-linkedlist-source-1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/java/java-linkedlist-source-1/" class="post-title-link" itemprop="url">【源码解析】想了解LinkedList？看这篇文章就对了</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-01-05 00:21:43" itemprop="dateCreated datePublished" datetime="2020-01-05T00:21:43+00:00">2020-01-05</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p>LinkedList由于实现了Deque这个接口，所以可以当栈和队列使用。不过一般要用栈或队列的时候推荐使用ArrayDeque,所以这里就不讲LinkedList的栈和队列功能了🌚。还是和上篇ArrayList一样，讲些常用的方法...</p>
          <!--noindex-->
            <div class="post-button">
              <a class="btn" href="/java/java-linkedlist-source-1/">
                阅读全文 &raquo;
              </a>
            </div>
          <!--/noindex-->
        
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/java/java-arraylist-source-1/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/java/java-arraylist-source-1/" class="post-title-link" itemprop="url">【源码解析】扒开ArrayList的外衣</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-01-03 19:13:31" itemprop="dateCreated datePublished" datetime="2020-01-03T19:13:31+00:00">2020-01-03</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <blockquote>
<p>积千里跬步，汇万里江河；每天进步一点点，终有一天将成大佬。</p>
</blockquote>
<h2 id="本文内容"><a href="#本文内容" class="headerlink" title="本文内容"></a>本文内容</h2><p>当然ArrayList里的方法不止这些，本文主要讲一些常用的方法</p>
<p><img src="http://cdn.mjava.top/blog/20200103101050.png" alt></p>
<h2 id="方法变量"><a href="#方法变量" class="headerlink" title="方法变量"></a>方法变量</h2><p><code>Arraylist</code>里的方法变量主要有以下几个</p>
<p><img src="http://cdn.mjava.top/blog/Selection_005.png" alt></p>
<h2 id="构造方法"><a href="#构造方法" class="headerlink" title="构造方法"></a>构造方法</h2><h3 id="有参构造"><a href="#有参构造" class="headerlink" title="有参构造"></a>有参构造</h3><h4 id="传入数组的大小"><a href="#传入数组的大小" class="headerlink" title="传入数组的大小"></a>传入数组的大小</h4><h5 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h5><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;(<span class="number">5</span>);</span><br></pre></td></tr></table></figure>

<h5 id="源码解析"><a href="#源码解析" class="headerlink" title="源码解析"></a>源码解析</h5><p><img src="http://cdn.mjava.top/blog/Selection_004.png" alt></p>
<h4 id="传入一个list对象"><a href="#传入一个list对象" class="headerlink" title="传入一个list对象"></a>传入一个list对象</h4><p>其实这个就相当于把传入的list对象里的数据<font color="orange">复制</font>到新的ArrayList对象</p>
<h5 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h5><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;(Arrays.asList(<span class="string">"z"</span>,<span class="string">"m"</span>,<span class="string">"h"</span>));</span><br></pre></td></tr></table></figure>

<blockquote>
<p>这里用来<code>Arrays</code>工具类里的<code>asList</code>方法，它的源码里是直接返回一个List，有兴趣的可以去看看，这里就不介绍了</p>
</blockquote>
<h5 id="源码解析-1"><a href="#源码解析-1" class="headerlink" title="源码解析"></a>源码解析</h5><p><img src="http://cdn.mjava.top/blog/Selection_006.png" alt></p>
<h3 id="无参构造"><a href="#无参构造" class="headerlink" title="无参构造"></a>无参构造</h3><p>这个比较简单，直接赋值一个空数组</p>
<h4 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-2"><a href="#源码解析-2" class="headerlink" title="源码解析"></a>源码解析</h4><p><img src="http://cdn.mjava.top/blog/20200103112943.png" alt></p>
<h2 id="add方法"><a href="#add方法" class="headerlink" title="add方法"></a>add方法</h2><p>add一般常用的有两个方法，一个就是<code>add(E e)</code>在尾部添加数据，一个就是<code>add(int index,E element)</code>在指定位置插入元素</p>
<h3 id="add-E-e"><a href="#add-E-e" class="headerlink" title="add(E e)"></a>add(E e)</h3><p>这个是<code>Arrayist</code>的主要方法，平时用的也是最多的方法之一，所以源码比较复杂，比较长</p>
<h4 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"灰灰HK"</span>);</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-3"><a href="#源码解析-3" class="headerlink" title="源码解析"></a>源码解析</h4><p><img src="http://cdn.mjava.top/blog/Selection_007.png" alt></p>
<ul>
<li><font color="orange">ensureCapacityInternal(int minCapacity)</font>确保数组容量充足</li>
</ul>
<p><img src="http://cdn.mjava.top/blog/Selection_009.png" alt></p>
<ul>
<li><font color="orange">calculateCapacity(Object[] elementData, int minCapacity)</font></li>
</ul>
<p><img src="http://cdn.mjava.top/blog/Selection_010.png" alt></p>
<ul>
<li>再回到<font color="orange">ensureExplicitCapacity(int minCapacity)</font>这个方法，这个方法先<code>修改次数加1</code>，然后判断<code>size+1</code>是不是比当前的数组容量大，如果比当前的数组容量大，则进行扩容操作，扩大容量为原数组的<code>1.5倍</code></li>
</ul>
<blockquote>
<p>比如第二次调用add方法，此时<code>size+1=2</code>, <code>elementData.length=10</code>,为什么等于10呢？因为第一次默认把数组容量从0扩大到了10,这时<code>size+1</code>比<code>elementData.length</code>小，就不会进行扩容操作</p>
</blockquote>
<p><img src="http://cdn.mjava.top/blog/Selection_011.png" alt></p>
<ul>
<li><font color="orange">grow(int minCapacity)</font>扩容</li>
</ul>
<blockquote>
<p>这里调用<code>Arrays.copyOf()</code>方法进行复制操作，当进一步深入这个方法时，发现是由<code>System.arraycopy()</code>这个方法实现复制功能的，这个方法由<code>native</code>关键字修饰，表示不是由<code>Java</code>语言实现的，一般是c/cpp实现</p>
</blockquote>
<p><img src="http://cdn.mjava.top/blog/Selection_012.png" alt></p>
<h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><p>到这里，add的方法流程就走完了，其核心步骤：</p>
<ul>
<li><p>每次添加元素时判断数组容量是否充足</p>
</li>
<li><p><font color="orange">第一次</font>添加元素，把数组容量扩容到10</p>
</li>
<li><p>扩容时，除第一次，以后的每次扩容为<font color="orange">原大小的1.5倍</font></p>
</li>
<li><p>扩容后调用<code>System.arraycopy()</code>方法把原数组的元素复制到扩容后的新数组</p>
</li>
</ul>
<h3 id="add-int-index-E-element"><a href="#add-int-index-E-element" class="headerlink" title="add(int index, E element)"></a>add(int index, E element)</h3><p>该方法为在指定位置插入元素，该位置及后面所有元素后移</p>
<h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"hk"</span>);</span><br><span class="line">list.add(<span class="number">0</span>,<span class="string">"灰灰"</span>);</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-4"><a href="#源码解析-4" class="headerlink" title="源码解析"></a>源码解析</h4><p><img src="http://cdn.mjava.top/blog/Selection_013.png" alt></p>
<blockquote>
<p>可以看到，这边又用到了<code>System.arraycopy()</code>这个方法</p>
</blockquote>
<ul>
<li><font color="orange">rangeCheckForAdd(int index)</font>判断是否越界</li>
</ul>
<blockquote>
<p>这里他是和<code>size</code>对比，而不是和数组的<code>length</code>对比，我个人认为这样第一节省了空间，第二方便后面移动的操作</p>
</blockquote>
<p><img src="http://cdn.mjava.top/blog/Selection_014.png" alt></p>
<ul>
<li><font color="orange">System.arraycopy()</font>拷贝数组</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">arraycopy</span><span class="params">(Object src,  <span class="keyword">int</span>  srcPos,</span></span></span><br><span class="line"><span class="function"><span class="params">                             		Object dest, <span class="keyword">int</span> destPos,</span></span></span><br><span class="line"><span class="function"><span class="params">                                    <span class="keyword">int</span> length)</span></span></span><br></pre></td></tr></table></figure>

<blockquote>
<ul>
<li>src    原数组对象</li>
<li>srcPos    原数组起始位置</li>
<li>dest    目标数组</li>
<li>destPos    目标数组起始位置</li>
<li>length    复制多少个数据</li>
</ul>
</blockquote>
<h4 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h4><p>插入方法其主要步骤如下:</p>
<ul>
<li>检查插入的位置是否越界</li>
<li>检查数组容量是否充足，不充足进行扩容相关操作</li>
<li>调用<code>System.arraycopy()</code>进行<code>index</code>及后面的元素后移</li>
</ul>
<h2 id="get方法"><a href="#get方法" class="headerlink" title="get方法"></a>get方法</h2><h3 id="get-int-index"><a href="#get-int-index" class="headerlink" title="get(int index)"></a>get(int index)</h3><h4 id="代码实现-5"><a href="#代码实现-5" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"hk"</span>);</span><br><span class="line">list.get(<span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-5"><a href="#源码解析-5" class="headerlink" title="源码解析"></a>源码解析</h4><p><img src="http://cdn.mjava.top/blog/Selection_015.png" alt></p>
<ul>
<li><font color="orange">rangeCheck(int index)</font>判断是否越界</li>
</ul>
<blockquote>
<p>get个add方法判断越界的方法是不一样的，这边是<code>index&gt;=size</code>,多了个<code>等于</code>，为什么要多个等于呢？因为数组是从0开始的，而size<font color="orange">相当于</font>是开始的从1开始的</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">rangeCheck</span><span class="params">(<span class="keyword">int</span> index)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (index &gt;= size)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IndexOutOfBoundsException(outOfBoundsMsg(index));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><font color="orange">elementData(int index)</font>直接返回对应下标的数组元素</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function">E <span class="title">elementData</span><span class="params">(<span class="keyword">int</span> index)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (E) elementData[index];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="小结-2"><a href="#小结-2" class="headerlink" title="小结"></a>小结</h4><p>get方法比较简单，主要步骤为：</p>
<ul>
<li>检查是否越界</li>
<li>返回对应元素</li>
</ul>
<h2 id="set方法"><a href="#set方法" class="headerlink" title="set方法"></a>set方法</h2><h3 id="set-int-index-E-element"><a href="#set-int-index-E-element" class="headerlink" title="set(int index, E element)"></a>set(int index, E element)</h3><h4 id="代码实现-6"><a href="#代码实现-6" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"hk"</span>);</span><br><span class="line">list.set(<span class="number">0</span>,<span class="string">"灰灰"</span>);</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-6"><a href="#源码解析-6" class="headerlink" title="源码解析"></a>源码解析</h4><p><img src="http://cdn.mjava.top/blog/Selection_016.png" alt></p>
<h2 id="remove方法"><a href="#remove方法" class="headerlink" title="remove方法"></a>remove方法</h2><h3 id="remove-int-index"><a href="#remove-int-index" class="headerlink" title="remove(int index)"></a>remove(int index)</h3><h4 id="代码实现-7"><a href="#代码实现-7" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"hk"</span>);</span><br><span class="line">list.remove(<span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-7"><a href="#源码解析-7" class="headerlink" title="源码解析"></a>源码解析</h4><blockquote>
<p>当删除的元素为最后一个元素时，<code>numMoved</code>就小于0了，就不会进行移动元素的操作</p>
</blockquote>
<p><img src="http://cdn.mjava.top/blog/Selection_017.png" alt></p>
<h3 id="remove-Object-o"><a href="#remove-Object-o" class="headerlink" title="remove(Object o)"></a>remove(Object o)</h3><blockquote>
<p>这个方法在实际中用的比较少，因为<code>AraryList</code>是可以保存重复的元素，所以删除是<font color="orange">删除最早添加的元素</font></p>
</blockquote>
<h4 id="代码实现-8"><a href="#代码实现-8" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"hk"</span>);</span><br><span class="line">list.remove(<span class="string">"hk"</span>);</span><br></pre></td></tr></table></figure>

<h4 id="源码解析-8"><a href="#源码解析-8" class="headerlink" title="源码解析"></a>源码解析</h4><p><img src="http://cdn.mjava.top/blog/Selection_018.png" alt></p>
<ul>
<li><font color="orange">fastRemove(int index)</font>删除元素</li>
</ul>
<blockquote>
<p>这个方法和remove(int index)内部的操作类似，不过这边不保存被删除的元素</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">fastRemove</span><span class="params">(<span class="keyword">int</span> index)</span> </span>&#123;</span><br><span class="line">    modCount++;</span><br><span class="line">    <span class="keyword">int</span> numMoved = size - index - <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">if</span> (numMoved &gt; <span class="number">0</span>)</span><br><span class="line">        System.arraycopy(elementData, index+<span class="number">1</span>, elementData, index,</span><br><span class="line">                         numMoved);</span><br><span class="line">    elementData[--size] = <span class="keyword">null</span>; <span class="comment">// clear to let GC do its work</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="clear方法"><a href="#clear方法" class="headerlink" title="clear方法"></a>clear方法</h2><h3 id="clear"><a href="#clear" class="headerlink" title="clear()"></a>clear()</h3><h4 id="代码实现-9"><a href="#代码实现-9" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List&lt;String&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">list.add(<span class="string">"hk"</span>);</span><br><span class="line">list.clear();</span><br></pre></td></tr></table></figure>

<h4 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h4><p><img src="http://cdn.mjava.top/blog/Selection_019.png" alt></p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><code>ArrayList</code>底层扩容或者移动数组元素时都调用了<code>System.arraycopy()</code>来进行相关操作，平时进行我们进行数组复制或移动的时候也可以调用这个方法了，这个性能比循环复制性能高多了，特别是在大量数据的时候。</p>
<p>文章好几次出现了<code>modCount++</code>这个操作，这个<code>modCount</code>主要用户内部类的迭代器</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://mjava.top/java/java-base-wei/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="灰灰">
      <meta itemprop="description" content="浅水是喧哗的，深水是沉默的">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="灰色World">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/java/java-base-wei/" class="post-title-link" itemprop="url">【图】用图片告诉你Java中的位运算</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-12-30 22:17:30" itemprop="dateCreated datePublished" datetime="2019-12-30T22:17:30+00:00">2019-12-30</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-01-27 10:07:24" itemprop="dateModified" datetime="2021-01-27T10:07:24+00:00">2021-01-27</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <p><img src="http://cdn.mjava.top/20191230221924.jpg" alt></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>​        虽然位运算在实际开发中并不常用,但是在各种算法中却常常见到它们的身影.因为是直接操作二进制的,所以机器执行起来就快很多,所以尽管实际业务中不常用,但如果你不想只做个码农,这个基础还是要掌握的;</p>
<p>讲位操作之前,就必须要知道<font color="orange">原码、反码、补码</font></p>
<blockquote>
<p>其中正数的<font color="orange">原码=反码=补码</font></p>
</blockquote>
<h2 id="原码、反码、补码"><a href="#原码、反码、补码" class="headerlink" title="原码、反码、补码"></a>原码、反码、补码</h2><blockquote>
<p>在机器的内存中,一个负数的表示是<font color="orange">这个负数的绝对值取原码,再取反码,再加一</font>,最后出现的就是这个负数在内存中的表示的二进制数值</p>
</blockquote>
<p>比如说-9在内存中的二进制码,这里用8位表示:</p>
<p><img src="http://cdn.mjava.top/20191230212102.png" alt></p>
<p>最后<font color="orange">-9在内存中的二进制值为11110111</font></p>
<blockquote>
<p>在二进制中,最高位为符号位,<font color="red">0代表正,1代表负</font></p>
</blockquote>
<h2 id="位运算"><a href="#位运算" class="headerlink" title="位运算"></a>位运算</h2><h3 id="左移和右移"><a href="#左移和右移" class="headerlink" title="左移和右移"></a>左移和右移</h3><p>在<code>Java</code>中的<code>int</code>类型有<font color="orange">4字节</font>,一个字节有<font color="orange">8位</font>,所以这边用32位表示一个数</p>
<h4 id="负数的左移和右移"><a href="#负数的左移和右移" class="headerlink" title="负数的左移和右移"></a>负数的左移和右移</h4><blockquote>
<p><font color="orange">这边负数表示是在内存中表示的二进制值</font></p>
<p>右移时:最高位<font color="orange">补符号位1</font></p>
<p>左移时:末尾补0</p>
</blockquote>
<p><img src="http://cdn.mjava.top/20191230212836.png" alt></p>
<h4 id="正数的左移和右移"><a href="#正数的左移和右移" class="headerlink" title="正数的左移和右移"></a>正数的左移和右移</h4><blockquote>
<p>右移时:最高位<font color="orange">补符号位0</font></p>
<p>左移时:末尾补0</p>
</blockquote>
<p><img src="http://cdn.mjava.top/20191230212951.png" alt></p>
<h3 id="无符号右移"><a href="#无符号右移" class="headerlink" title="无符号右移"></a>无符号右移</h3><blockquote>
<p>无论是正数还是负数,右移<font color="orange">最高位一律补0</font></p>
</blockquote>
<p><img src="http://cdn.mjava.top/20191230213359.png" alt></p>
<h3 id="amp-位与"><a href="#amp-位与" class="headerlink" title="&amp;(位与)"></a>&amp;(位与)</h3><blockquote>
<p>当相对应的位都为1时,等于1,否则等于0</p>
</blockquote>
<p>为了方便表示,接下来全部都用8位表示一个数</p>
<p><img src="http://cdn.mjava.top/20191230215214.png" alt></p>
<h3 id="位或"><a href="#位或" class="headerlink" title="|(位或)"></a>|(位或)</h3><blockquote>
<p>当相对应的位有一个为1时,等于1,否则等于0</p>
</blockquote>
<p><img src="http://cdn.mjava.top/20191230215609.png" alt></p>
<h3 id="异或"><a href="#异或" class="headerlink" title="^(异或)"></a>^(异或)</h3><blockquote>
<p>当相对应的位不同时,等于1,相同时等于0</p>
</blockquote>
<p><img src="http://cdn.mjava.top/20191230220948.png" alt></p>
<h3 id="取反"><a href="#取反" class="headerlink" title="~(取反)"></a>~(取反)</h3><blockquote>
<p>1等于0,0等于1</p>
</blockquote>
<p><img src="http://cdn.mjava.top/20191230220449.png" alt></p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><table>
<thead>
<tr>
<th>含义</th>
<th>运算符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>左移</td>
<td>&lt;&lt;</td>
<td>末尾补0</td>
</tr>
<tr>
<td>右移</td>
<td>&gt;&gt;</td>
<td>负数:最高位<font color="orange">补符号位1</font>      正数:最高位<font color="orange">补符号位0</font></td>
</tr>
<tr>
<td>无符号右移</td>
<td>&gt;&gt;&gt;</td>
<td>无论是正数还是负数,右移<font color="orange">最高位一律补0</font></td>
</tr>
<tr>
<td>&amp;(位与)</td>
<td>&amp;</td>
<td>当相对应的位都为1时,等于1,否则等于0</td>
</tr>
<tr>
<td>|(位或)</td>
<td>|</td>
<td>当相对应的位有一个为1时,等于1,否则等于0</td>
</tr>
<tr>
<td>^(异或)</td>
<td>^</td>
<td>当相对应的位 不同时,等于1  相同时,等于0</td>
</tr>
<tr>
<td>~(取反)</td>
<td>~</td>
<td>1等于0,0等于1</td>
</tr>
</tbody></table>
<blockquote>
<p>最后有个小技巧,<font color="orange">向左位移几位就是乘以2的几次方,比如9向左移n位,就是</font></p>
</blockquote>
<p>$$<br>9向左移n位=9*2^n<br>$$</p>
<blockquote>
<p><font color="orange">向右移几位就是除以2的几次方然后向下取整,比如9向右移动n位,就是</font></p>
</blockquote>
<p>$$<br>9向右移n位=⌊9/2^n⌋<br>$$</p>
<p><font color="red">注:⌊⌋是数学符号向下取整,例如:2.25向下取整是2;   -2.25向下取整是-3; 具体的话可以看看这篇文章<a href="https://www.shuxuele.com/sets/function-floor-ceiling.html" rel="noopener external nofollow noreferrer" target="_blank">向上取整与向下取整函数</a>;该技巧不适用无符号右移</font></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  


  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/2/"><i class="fa fa-angle-left" aria-label="上一页"></i></a><a class="page-number" href="/">1</a><a class="page-number" href="/page/2/">2</a><span class="page-number current">3</span><a class="page-number" href="/page/4/">4</a><span class="space">&hellip;</span><a class="page-number" href="/page/6/">6</a><a class="extend next" rel="next" href="/page/4/"><i class="fa fa-angle-right" aria-label="下一页"></i></a>
  </nav>



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">灰灰</p>
  <div class="site-description" itemprop="description">浅水是喧哗的，深水是沉默的</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">59</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">16</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">56</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/greycode9" title="GitHub → https://github.com/greycode9" rel="noopener external nofollow noreferrer" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:zhengminghui99@gmail.com" title="E-Mail → mailto:zhengminghui99@gmail.com" rel="noopener external nofollow noreferrer" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      Links
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://www.yuque.com/huihui-r7gwx" title="https://www.yuque.com/huihui-r7gwx" rel="noopener external nofollow noreferrer" target="_blank">语雀</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        
  <div class="beian"><a href="https://beian.miit.gov.cn" rel="noopener external nofollow noreferrer" target="_blank">赣ICP备17003482号 </a>
  </div>

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">灰灰</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io" class="theme-link" rel="noopener external nofollow noreferrer" target="_blank">Hexo</a> & <a href="https://muse.theme-next.org" class="theme-link" rel="noopener external nofollow noreferrer" target="_blank">NexT.Muse</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>
<script src="/js/utils.js"></script><script src="/js/motion.js"></script>
<script src="/js/schemes/muse.js"></script>
<script src="/js/next-boot.js"></script>



  




  <script src="/js/local-search.js"></script>












  

  
      

<script>
  if (typeof MathJax === 'undefined') {
    window.MathJax = {
      loader: {
          load: ['[tex]/mhchem'],
        source: {
          '[tex]/amsCd': '[tex]/amscd',
          '[tex]/AMScd': '[tex]/amscd'
        }
      },
      tex: {
        inlineMath: {'[+]': [['$', '$']]},
          packages: {'[+]': ['mhchem']},
        tags: 'ams'
      },
      options: {
        renderActions: {
          findScript: [10, doc => {
            document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
              const display = !!node.type.match(/; *mode=display/);
              const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
              const text = document.createTextNode('');
              node.parentNode.replaceChild(text, node);
              math.start = {node: text, delim: '', n: 0};
              math.end = {node: text, delim: '', n: 0};
              doc.math.push(math);
            });
          }, '', false],
          insertedScript: [200, () => {
            document.querySelectorAll('mjx-container').forEach(node => {
              let target = node.parentNode;
              if (target.nodeName.toLowerCase() === 'li') {
                target.parentNode.classList.add('has-jax');
              }
            });
          }, '', false]
        }
      }
    };
    (function () {
      var script = document.createElement('script');
      script.src = '//cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
      script.defer = true;
      document.head.appendChild(script);
    })();
  } else {
    MathJax.startup.document.state(0);
    MathJax.texReset();
    MathJax.typeset();
  }
</script><!-- hexo-inject:begin --><!-- hexo-inject:end -->

    

  

</body>
</html>
